<?php

/**
 * @file 检查任务
 */

if (empty($_args['type']) || $_args['type'] == 'update') {
  ___cron_check_update();
} else {
  ___cron_check_kill();
}

// protected ___cron_check_update() {{{ 
/**
 * ___cron_check_update
 *  检查服务器上运行的任务状态，并更新检查时间
 * 
 * @access protected
 * @return void
 */
function ___cron_check_update() {
  // 在 cron_history 正常执行的情况下，cron 数据量较小，读取全表比使用 group by 或 distinct 效率更高
  if ($fetch = db_query('SELECT * FROM {cron}')) {
    $process = _cron_get_php_ps();
    $server_name = php_uname('n');
    foreach ($fetch as $v) {
      //该任务正在当前服务器执行
      if (!empty($process[$v->cid])) {
        $cron = $process[$v->cid];
        // 若 status 已设为 3，表示系统认为任务已完成，该任务应当 kill
        if ($v->status == 3) {
          exec('kill -9 ' . $cron['pid'] . ' > /dev/null &');
          db_exec('UPDATE {cron} SET status = 3, updated = ? WHERE cid = ?', array(time(), $v->cid));
          dd_log('cron_timeout', t('system', '已终止超时任务 !command，pid：!pid，system：!name，运行 !time 秒', array(
            '!command' => $cron['command'], '!pid' => $cron['pid'], '!name' => $server_name, '!time' => time()-$v->created)));
        } else {
          // 写入最新运行时间
          db_exec('UPDATE {cron} SET updated = ? WHERE cid = ?',
          array(time(), $v->cid));
          $time = time()-$v->created;
          if ($time > 600) {
            dd_log('cron_timeout', t('system', '任务 !command 已运行超过 !time 秒了，pid：!pid，system：!name', array(
              '!command' => $cron['command'], '!time' => $time, '!pid' => $cron['pid'], '!name' => $server_name)));
          }
        }
      } else if ($v->status == 1) {
        $v->data = unserialize($v->data);
        // 任务在本机执行，但后台已不存在，表示已执行完成
        if (!empty($v->data['server']) && $v->data['server'] == $server_name) {
          db_exec('UPDATE {cron} SET status = 2, updated = ? WHERE cid = ?', array(time(), $v->cid));
        }
      }
    }
  }
}
// }}}

// protected ___cron_check_kill() {{{ 
/**
 * ___cron_check_kill
 *  检查待杀死的任务
 * 
 * @access protected
 * @return void
 */
function ___cron_check_kill() {
  // 模块所有任务
  module_include_file('cronjobs.inc');
  $cronjobs = _module_invoke_all('cronjobs', 0);

  // 默认超时即kill进程的时间，若为 0，则忽略
  $timeout = var_get('cron_timeout_kill', 3600);
  
  // 默认无响应即kill进程的时间，若为 0，则忽略
  $error_time = var_get('cron_error_time', 600);

  if ($fetch = db_query('SELECT * FROM {cron} WHERE status = 1')) {

    foreach ($fetch as $o) {
      // 若进程在执行中，正常情况下，每分钟会上报一次状态（即更新 updated 字段），若未更新，可能服务器进程已死掉
      if (!empty($error_time) && $error_time < (time()-$o->updated)) {
        // 修改状态为 3，强行终止运行，在下次服务器执行 cron_check 任务时，将 kill 掉对应进程
        db_exec('UPDATE {cron} SET status = 3, updated = ? WHERE cid = ?', array(time(), $o->cid));
        continue;
      }

      //任务已执行时间
      $time = $o->updated-$o->created;
      if (!empty($timeout) && $timeout < $time) {
        // 修改状态为 3，强行终止运行，在下次服务器执行 cron_check 任务时，将 kill 掉对应进程
        db_exec('UPDATE {cron} SET status = 3, updated = ? WHERE cid = ?', array(time(), $o->cid));
        continue;
      }

      // 判断执行时间是否超过任务中的设置
      $data = unserialize($o->data);
      if (!empty($cronjobs[$data['module']]) && !empty($cronjobs[$data['module']][$data['type']])) {
        if (!empty($cronjobs[$data['module']][$data['type']]['timeout'])) {
          if ($cronjobs[$data['module']][$data['type']]['timeout'] < $time) {
            // 修改状态为 3，强行终止运行，在下次服务器执行 cron_check 任务时，将 kill 掉对应进程
            db_exec('UPDATE {cron} SET status = 3, updated = ? WHERE cid = ?', array(time(), $o->cid));
            continue;
          }
        }
      }
    }
  }
}
// }}}
